//
// Created by LONG on 2020/10/12.
//

#include <netinet/in.h>
#include <netinet/sctp.h>
#include <arpa/inet.h>
#include "../include/sctpApi.h"
#include "../../misc/include/misc.h"

int32_t SCTPC_Init(int *fd)
{
    int32_t rc;
    struct sctp_event_subscribe evnts;

    *fd = socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP);
    IF_RETURN(==, -1, *fd, O5G_RC_ER, "SCTPC_Init() socket() error!\n");

    bzero(&evnts, sizeof(evnts));
    evnts.sctp_data_io_event = 1;
    evnts.sctp_shutdown_event = 1;
    rc = setsockopt(*fd, IPPROTO_SCTP, SCTP_EVENTS, &evnts, sizeof(evnts));
    IF_RETURN(!=, 0, rc, O5G_RC_ER, "SCTPC_Init() setsockopt() error!\n");

    return O5G_RC_OK;
}

int32_t SCTPC_Connect(int fd, const char* ip, uint16_t port)
{
    int32_t rc;
    struct sockaddr_in svcAddr;

    bzero(&svcAddr, sizeof(svcAddr));
    svcAddr.sin_family = AF_INET;
    inet_pton(AF_INET, ip, &svcAddr.sin_addr);
    svcAddr.sin_port = htons(port);
    rc = connect(fd, (struct sockaddr*)&svcAddr, sizeof(svcAddr));
    IF_RETURN(!=, 0, rc, O5G_RC_ER, "SCTPC_Connect() connect() error!\n");

    return O5G_RC_OK;
}

int32_t SCTPC_Final(int fd)
{
    shutdown(fd, SHUT_RDWR);
    usleep(1000);
    return close(fd);
}

int32_t SCTPS_Init(int *fd)
{
    int32_t rc;
    struct sctp_event_subscribe evnts;

    *fd = socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP);
    IF_RETURN(==, -1, *fd, O5G_RC_ER, "SCTPS_Init() socket() error!\n");

    bzero(&evnts, sizeof(evnts));
    evnts.sctp_data_io_event = 1;
    evnts.sctp_shutdown_event = 1;
    rc = setsockopt(*fd, IPPROTO_SCTP, SCTP_EVENTS, &evnts, sizeof(evnts));
    IF_RETURN(!=, 0, rc, O5G_RC_ER, "SCTPS_Init() setsockopt() error!\n");

    return O5G_RC_OK;
}

int32_t SCTPS_Bind(int fd, const char* ip, uint16_t port)
{
    int32_t rc;
    struct sockaddr_in svcAddr;

    bzero(&svcAddr, sizeof(svcAddr));
    svcAddr.sin_family = AF_INET;
    inet_pton(AF_INET, ip, &svcAddr.sin_addr);
    svcAddr.sin_port = htons(port);
    rc = bind(fd, (struct sockaddr*)&svcAddr, sizeof(svcAddr));
    IF_RETURN(!=, 0, rc, O5G_RC_ER, "SCTPS_Bind() bind() error!\n");

    return O5G_RC_OK;
}

int32_t SCTPS_Listen(int fd)
{
    int32_t rc;

    rc = listen(fd, SOMAXCONN);
    IF_RETURN(!=, 0, rc, O5G_RC_ER, "SCTPS_Listen() listen() error!\n");

    return O5G_RC_OK;
}

int32_t SCTPS_Final(int fd)
{
    shutdown(fd, SHUT_RDWR);
    usleep(1000);
    return close(fd);
}
